#include "ipc.h"

#include "main.h"

#include <iostream>
#include <set>

wxString DialogTopic = wxT("DialogTopic");
wxString DialogParam = wxT("EndParameters");

class IpcConnection;
class IpcClient;
typedef std::set<IpcConnection*> IpcConnections;
IpcConnections ipc_connections;
bool ipc_client_can_close = false;
IpcClient *ipc_client = NULL;

class IpcConnection : public wxConnection
{
protected:
	virtual bool OnDisconnect(void)
	{
		if (ipc_client)
		{
			if (!ipc_client_can_close) /* server disconnected before we finished our job */
				exit(1);
		} else
		{
			/* server : track clients */
			IpcConnections::iterator i = ipc_connections.find(this);
			if (i != ipc_connections.end())
				ipc_connections.erase(i);
		}
		return wxConnection::OnDisconnect();
	}
	virtual bool OnAdvise(const wxString& topic, const wxString& item, wxChar* data, int size, wxIPCFormat format)
	{ /* client : server closing and sending us results (an utf8 string ready to be printed)*/
		if (size>0)
		{
			std::cout << wxString(data, size/sizeof(wxChar)).utf8_str();
		}
		ipc_close_client();
		exit(0);
	}
	virtual bool OnExecute(const wxString& topic, wxChar* data, int size, wxIPCFormat format)
	{ /* server : close request */
		wxASSERT(wxString(data) == wxT("close"));
		close_main_window();
		return true;
	}
	virtual bool OnPoke(const wxString& topic, const wxString& item, wxChar* data, int size, wxIPCFormat format)
	{ /* server : update parameters */
		wxASSERT(item == DialogParam);
		wxString params(data, size/sizeof(wxChar));
		wxGetApp().update_parameters(params);
		return true;
	}
	virtual bool OnStartAdvise(const wxString& topic, const wxString& item)
	{ /* server : client wants to wait for us */
		return item == DialogParam;
	}
	virtual bool OnStopAdvise(const wxString& topic, const wxString& item)
	{
		return item == DialogParam;
	}


};

class IpcServer : public wxServer
{
	virtual wxConnectionBase* OnAcceptConnection(const wxString& topic)
	{
		if (topic != DialogTopic)
			return NULL;
		IpcConnection *connection = new IpcConnection;
		ipc_connections.insert(connection);
		return connection;
	}
}* ipc_server = NULL;

class IpcClient : public wxClient
{
	virtual wxConnectionBase* OnMakeConnection()
	{
		return new IpcConnection;
	}
};

wxString ipc_create_server(wxString& service)
{
	ipc_server = new IpcServer();
	if (!ipc_server->Create(service))
	{
		wxASSERT(false);
		delete ipc_server;
		ipc_server = NULL;
		return wxEmptyString;
	}
	return service;
}

wxConnectionBase* ipc_client_connect(wxString& service)
{
	ipc_client = new IpcClient;
	wxConnectionBase* cb = ipc_client->MakeConnection(wxT("localhost"), service, DialogTopic);
	if (!cb)
	{
//		std::cerr << "Cannot find Dialog server" << std::endl;
		exit(-42);
	}
	return cb;
}

void ipc_wait_result(wxConnectionBase* cb)
{
	cb->StartAdvise(DialogParam);
}

void ipc_close_server(const wxString& a)
{
	for(IpcConnections::iterator i = ipc_connections.begin(); i != ipc_connections.end(); i++)
	{
		wxConnectionBase* cb = *i;
		cb->Advise(DialogParam, (wxChar*)a.data(), a.Len()*sizeof(wxChar));
		cb->Disconnect();
		delete cb;
	}
	ipc_connections.clear();
	delete ipc_server;
}

void ipc_close_client(void)
{
	ipc_client_can_close = true;
	delete ipc_client;
}
